package com.myk.game.gobangchess.ai.symmetric;

import java.util.*;

/**
 * GameStateUpdater 类提供了静态方法来局部更新 GameState 对象。
 * 这些方法通过添加或移除单个棋子来高效地修改棋盘状态，
 * 避免了对整个棋盘的重新计算。
 */
public class GameStateUpdater {

    /**
     * 从给定的 GameState 中移除一个棋子，并相应地更新所有相关的棋块信息。
     *
     * @param state 要修改的 GameState 对象。
     * @param row   要移除棋子的行坐标 (0-14)。
     * @param col   要移除棋子的列坐标 (0-14)。
     */
    public static void removePiece(GameState state, int row, int col) {
        int color = state.board[row][col];
        if (color == 0) {
            // 指定位置没有棋子，直接返回
            return;
        }

        // 1. 更新棋盘矩阵和总棋子数
        state.board[row][col] = 0;
        state.totalPieceCount--;

        // 2. 找到包含该棋子的棋块及其索引
        List<List<int[]>> blocks = state.allBlocks.get(color);
        int blockIndex = -1;
        List<int[]> originalBlock = null;
        for (int i = 0; i < blocks.size(); i++) {
            for (int[] piece : blocks.get(i)) {
                if (piece[0] == row && piece[1] == col) {
                    originalBlock = blocks.get(i);
                    blockIndex = i;
                    break;
                }
            }
            if (originalBlock != null) break;
        }

        if (originalBlock == null) {
            // 理论上不应发生，除非 GameState 不一致
            return;
        }

        // 3. 从 GameState 中移除旧棋块的所有信息
        state.allBlocks.get(color).remove(blockIndex);
        state.blockSymmetries.get(color).remove(blockIndex);
        state.blockBoundingBoxes.get(color).remove(blockIndex);
        state.blockSizes.get(color).remove(blockIndex);
        state.blockSurroundingPoints.get(color).remove(blockIndex);
        if (color == 1) state.blackBlockCount--;
        else state.whiteBlockCount--;

        // 4. 处理棋块分裂
        if (originalBlock.size() > 1) {
            int[][] tempBoard = new int[15][15];
            for (int[] piece : originalBlock) {
                if (piece[0] != row || piece[1] != col) {
                    tempBoard[piece[0]][piece[1]] = color;
                }
            }

            // 使用 GameStateGenerator 分析分裂后的新棋块
            GameState tempState = GameStateGenerator.getGameState(tempBoard);
            List<List<int[]>> newBlocks = tempState.allBlocks.get(color);

            if (newBlocks != null && !newBlocks.isEmpty()) {
                // 5. 将新棋块信息合并回主 GameState
                for (int i = 0; i < newBlocks.size(); i++) {
                    List<int[]> newBlock = tempState.allBlocks.get(color).get(i);
                    List<int[]> newSurroundingPoints = tempState.blockSurroundingPoints.get(color).get(i);

                    // 修正新棋块的周围空位列表
                    newSurroundingPoints.removeIf(p -> state.board[p[0]][p[1]] != 0);

                    state.allBlocks.get(color).add(newBlock);
                    state.blockSymmetries.get(color).add(tempState.blockSymmetries.get(color).get(i));
                    state.blockBoundingBoxes.get(color).add(tempState.blockBoundingBoxes.get(color).get(i));
                    state.blockSizes.get(color).add(tempState.blockSizes.get(color).get(i));
                    state.blockSurroundingPoints.get(color).add(newSurroundingPoints);
                }
                if (color == 1) state.blackBlockCount += newBlocks.size();
                else state.whiteBlockCount += newBlocks.size();
            }
        }

        // 6. 更新周围对手棋块的相邻空位列表
        int opponentColor = -color;
        int[] removedPos = {row, col};
        int[] dr = {-1, -1, -1, 0, 0, 1, 1, 1};
        int[] dc = {-1, 0, 1, -1, 1, -1, 0, 1};

        Set<Integer> updatedOpponentBlockIndices = new HashSet<>();
        for (int i = 0; i < 8; i++) {
            int nr = row + dr[i];
            int nc = col + dc[i];
            if (nr >= 0 && nr < 15 && nc >= 0 && nc < 15 && state.board[nr][nc] == opponentColor) {
                // 找到这个对手棋子所在的棋块
                List<List<int[]>> opponentBlocks = state.allBlocks.get(opponentColor);
                for (int j = 0; j < opponentBlocks.size(); j++) {
                    if (updatedOpponentBlockIndices.contains(j)) continue;
                    for (int[] piece : opponentBlocks.get(j)) {
                        if (piece[0] == nr && piece[1] == nc) {
                            state.blockSurroundingPoints.get(opponentColor).get(j).add(removedPos);
                            updatedOpponentBlockIndices.add(j);
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * 向给定的 GameState 中添加一个棋子，并相应地更新所有相关的棋块信息。
     *
     * @param state 要修改的 GameState 对象。
     * @param row   要添加棋子的行坐标 (0-14)。
     * @param col   要添加棋子的列坐标 (0-14)。
     * @param color 要添加棋子的颜色 (1:黑, -1:白)。
     */
    public static void addPiece(GameState state, int row, int col, int color) {
        if (state.board[row][col] != 0) {
            // 指定位置已有棋子，直接返回
            return;
        }

        // 1. 更新棋盘矩阵和总棋子数
        state.board[row][col] = color;
        state.totalPieceCount++;

        // 2. 查找所有相邻的同色棋块以进行合并
        int[] dr = {-1, -1, -1, 0, 0, 1, 1, 1};
        int[] dc = {-1, 0, 1, -1, 1, -1, 0, 1};

        Map<Integer, List<int[]>> blocksToMerge = new HashMap<>(); // <Index, Block>
        List<List<int[]>> sameColorBlocks = state.allBlocks.get(color);

        for (int i = 0; i < 8; i++) {
            int nr = row + dr[i];
            int nc = col + dc[i];
            if (nr >= 0 && nr < 15 && nc >= 0 && nc < 15 && state.board[nr][nc] == color) {
                for (int j = 0; j < sameColorBlocks.size(); j++) {
                    if (blocksToMerge.containsKey(j)) continue;
                    for (int[] piece : sameColorBlocks.get(j)) {
                        if (piece[0] == nr && piece[1] == nc) {
                            blocksToMerge.put(j, sameColorBlocks.get(j));
                            break;
                        }
                    }
                }
            }
        }

        // 3. 从 GameState 中移除待合并的旧棋块
        List<Integer> indicesToRemove = new ArrayList<>(blocksToMerge.keySet());
        indicesToRemove.sort(Collections.reverseOrder()); // 从大到小删除，避免索引错乱

        for (int index : indicesToRemove) {
            state.allBlocks.get(color).remove(index);
            state.blockSymmetries.get(color).remove(index);
            state.blockBoundingBoxes.get(color).remove(index);
            state.blockSizes.get(color).remove(index);
            state.blockSurroundingPoints.get(color).remove(index);
        }
        if (color == 1) state.blackBlockCount -= indicesToRemove.size();
        else state.whiteBlockCount -= indicesToRemove.size();

        // 4. 创建临时棋盘，生成合并后的新棋块
        int[][] tempBoard = new int[15][15];
        tempBoard[row][col] = color;
        for (List<int[]> block : blocksToMerge.values()) {
            for (int[] piece : block) {
                tempBoard[piece[0]][piece[1]] = color;
            }
        }

        GameState tempState = GameStateGenerator.getGameState(tempBoard);
        List<List<int[]>> newBlocks = tempState.allBlocks.get(color);

        // 5. 将新棋块信息合并回主 GameState
        if (newBlocks != null && !newBlocks.isEmpty()) {
            List<int[]> newBlock = newBlocks.get(0);
            List<int[]> newSurroundingPoints = tempState.blockSurroundingPoints.get(color).get(0);

            // 修正新棋块的周围空位列表
            newSurroundingPoints.removeIf(p -> state.board[p[0]][p[1]] != 0);

            state.allBlocks.get(color).add(newBlock);
            state.blockSymmetries.get(color).add(tempState.blockSymmetries.get(color).get(0));
            state.blockBoundingBoxes.get(color).add(tempState.blockBoundingBoxes.get(color).get(0));
            state.blockSizes.get(color).add(tempState.blockSizes.get(color).get(0));
            state.blockSurroundingPoints.get(color).add(newSurroundingPoints);

            if (color == 1) state.blackBlockCount++;
            else state.whiteBlockCount++;
        }

        // 6. 更新周围对手棋块的相邻空位列表
        int opponentColor = -color;
        for (int i = 0; i < 8; i++) {
            int nr = row + dr[i];
            int nc = col + dc[i];
            if (nr >= 0 && nr < 15 && nc >= 0 && nc < 15 && state.board[nr][nc] == opponentColor) {
                // 找到这个对手棋子所在的棋块
                List<List<int[]>> opponentBlocks = state.allBlocks.get(opponentColor);
                for (int j = 0; j < opponentBlocks.size(); j++) {
                    List<int[]> surroundingPoints = state.blockSurroundingPoints.get(opponentColor).get(j);
                    // 使用迭代器安全删除
                    surroundingPoints.removeIf(p -> p[0] == row && p[1] == col);
                }
            }
        }
    }

    /**
     * 用于验证功能的 main 方法。
     */
    public static void main(String[] args) {
        // 1. 初始化一个包含多个棋块的棋盘
        int[][] board = new int[15][15];
        // 黑棋 'C' 形
        board[2][2] = 1; board[2][3] = 1; board[2][4] = 1;
        board[3][2] = 1;
        board[4][2] = 1; board[4][3] = 1; board[4][4] = 1;
        // 另一个独立的黑棋
        board[6][6] = 1;
        // 白棋，用于测试合并
        board[8][8] = -1;
        board[8][10] = -1;
        // 另一个独立的黑棋
        board[10][10] = 1;

        System.out.println("### 初始棋盘 ###");
        BoardPrinter.printBoardWithIndices(board);

        // 2. 获取初始状态并打印所有棋块信息
        GameState state = GameStateGenerator.getGameState(board);
        System.out.println("\n########################################");
        System.out.println("### 添加前各棋块信息 ###");
        GameStatePrinter.printAllBlockDetails(state);
        System.out.println("########################################\n");

        // 3. 执行操作：在(9, 9)添加一个白棋
        System.out.println("### 执行操作: 在 (9, 9) 添加白棋 (-1) ###");
        addPiece(state, 9, 9, -1);
        System.out.println("\n操作完成。\n");

        // 4. 打印更新后的棋盘和所有棋块信息
        System.out.println("### 添加后棋盘 ###");
        BoardPrinter.printBoardWithIndices(state.board);
        System.out.println("\n########################################");
        System.out.println("### 添加后各棋块信息 ###");
        GameStatePrinter.printAllBlockDetails(state);
        System.out.println("########################################");

        // 5. 执行操作：在(9, 9)移除一个白棋
        System.out.println("### 执行操作: 在 (9, 9) 添加白棋 (-1) ###");
        removePiece(state, 9, 9);
        System.out.println("\n操作完成。\n");

        // 6. 打印更新后的棋盘和所有棋块信息
        System.out.println("### 移除后棋盘 ###");
        BoardPrinter.printBoardWithIndices(state.board);
        System.out.println("\n########################################");
        System.out.println("### 移除后各棋块信息 ###");
        GameStatePrinter.printAllBlockDetails(state);
        System.out.println("########################################");
    }
}